{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.1 什么是并发"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 计算机系统中的并发 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**并发**（concurrency）是两个或多个同时独立进行的活动"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "若我们谈及计算机系统中的**并发**，则是指同一个系统中，多个独立活动同时进行，而非依次进行。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "硬件并发（hardware concurrency）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "两种并发方式：双核机上的并发执行与单核机上的任务切换\n",
    "\n",
    "<img src=\"./images/1.1.png\" alt=\"Figure 1.1\" style=\"zoom:50%;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "真正需要注意的关键因素是硬件支持的线程数（hardware threads），也就是硬件自身真正支持同时运行的独立任务的数量。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 并发的方式 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多进程并发"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将一个应用软件拆分成多个独立进程同时运行，它们都只含单一线程，非常类似于同时运行浏览器和文字处理软件\n",
    "\n",
    "<img src=\"./images/1.3.png\" alt=\"Figure 1.3\" style=\"zoom:50%;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多线程并发"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在单一进程内运行多线程\n",
    "\n",
    "<img src=\"./images/1.4.png\" alt=\"Figure 1.4\" style=\"zoom:50%;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程非常像轻量级进程：每个线程都独立运行，并能各自执行不同的指令序列。不过，同一进程内的所有线程都共用相同的地址空间，且所有线程都能直接访问大部分数据。全局变量依然全局可见，指向对象或数据的指针和引用能在线程间传递。尽管进程间共享内存通常可行，但这种做法设置复杂，往往难以驾驭，原因是同一数据的地址在不同进程中不一定相同"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 并发与并行 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "就多线程代码而言，并发与并行（parallel）的含义很大程度上相互重叠。\n",
    "\n",
    "两个术语都是指使用可调配的硬件资源同时运行多个任务，但并行更强调性能。\n",
    "- 当人们谈及并行时，主要关心的是利用可调配的硬件资源提升大规模数据处理的性能\n",
    "- 当谈及并发时，主要关心的是分离关注点或响应能力。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.2 为什么使用并发技术"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "应用软件使用并发技术的主要原因有两个：分离关注点与性能提升。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 为分离关注点而并发 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一直以来，编写软件时，**分离关注点**（separation of concerns）几乎总是不错的构思：归类相关代码，隔离无关代码，使程序更易于理解和测试，因此所含缺陷很可能更少"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程间交互得以限定于代码中可明确辨识的切入点，而无须将不同任务的逻辑交错散置"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "线程的实际数量与 CPU 既有的内核数量无关，因为用线程分离关注点的依据是设计理念，不以增加运算吞吐量为目的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 为性能而并发：任务并行和数据并行 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "增强性能的并发方式有两种。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第一种\n",
    "- 最直观地，将单一任务分解成多个部分，各自并行运作，从而节省总运行耗时。此方式即为**任务并行**。尽管听起来浅白、直接，但这却有可能涉及相当复杂的处理过程，因为任务各部分之间也许存在纷繁的依赖。任务分解可以针对处理过程，调度某线程运行同一算法的某部分，另一线程则运行其他部分\n",
    "- 也可以针对数据，线程分别对数据的不同部分执行同样的操作，这被称为**数据并行**\n",
    "\n",
    "\n",
    "> 易于采用上述并行方式的算法常常被称为尴尬并行(embarrasingly parallel)算法。其含义是，将算法的代码并行化实在简单，甚至简单得会让我们尴尬，实际上这是好事。我还遇见过用其他术语描述这类算法，叫“天然并行”（naturally parallel）与“方便并发”（conveniently concurrent）。尴尬并行算法具备的优良特性是可按规模伸缩—只要硬件支持的线程数目增加，算法的并行程度就能相应提升。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "第二种增强性能的并发方式是利用并行资源解决规模更大的问题。\n",
    "\n",
    "采用这种方式处理单一数据所需的时间依旧不变，而同等时间内能处理的数据相对更多"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 什么时候避免并发 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "知道何时避免并发，与知道何时采用并发同等重要\n",
    "\n",
    "编写正确运行的多线程代码需要额外的开发时间和相关维护成本，除非潜在的性能提升或分离关注点而提高的清晰度值得这些开销，否则别使用并发技术\n",
    "\n",
    "- 性能增幅可能不如预期\n",
    "- 线程是一种有限的资源。若一次运行太多线程，便会消耗操作系统资源，可能令系统整体变慢. 由于每个线程都需要独立的栈空间1，如果线程太多，就可能耗尽所属进程的可用内存或地址空间. 4GB = 4096*1MB\n",
    "- 在服务器端，客户端/服务器（Client/Server，C/S）模式的应用程序为每个连接发起一个独立的线程。如果只有少量连接，这尚能良好工作。不过，请求量巨大的服务器需要处理的连接数目庞大，若采用同样的方法，就会发起过多线程而很快耗尽系统资源。针对这一情形，如果要达到最优性能，便须谨慎使用线程池\n",
    "- 运行的线程越多，操作系统所做的上下文切换就越频繁，每一次切换都会减少本该用于实质工作的时间。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.3 并发与 C++多线程"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C++线程库的某些型别有可能提供成员函数`native_handle()`，允许它的底层直接运用平台专属的 API。因其本质使然，任何采用`native_handle()`的操作都完全依赖于特定平台，这也超出了本书的范围（以及 C++标准库)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1.4 启程上路"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// https://godbolt.org/z/5dfeMzM57\n",
    "\n",
    "#include <iostream>\n",
    "#include <thread>\n",
    "\n",
    "void hello() {\n",
    "    std::cout << \"Hello Concurrent World\\n\";\n",
    "}\n",
    "\n",
    "int main() {\n",
    "    std::thread t{ hello };\n",
    "    t.join();\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
